package com.yupi.yoj.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yupi.yoj.common.ErrorCode;
import com.yupi.yoj.constant.CommonConstant;
import com.yupi.yoj.exception.BusinessException;
import com.yupi.yoj.exception.ThrowUtils;
import com.yupi.yoj.mapper.QuestionMapper;
import com.yupi.yoj.model.dto.contest.ContestQueryTeamListByTidsRequest;
import com.yupi.yoj.model.dto.post.PostEsDTO;
import com.yupi.yoj.model.dto.post.PostQueryRequest;
import com.yupi.yoj.model.dto.question.QuestionEsDTO;
import com.yupi.yoj.model.dto.question.QuestionQueryRequest;
import com.yupi.yoj.model.entity.*;
import com.yupi.yoj.model.vo.PostVO;
import com.yupi.yoj.model.vo.QuestionVO;
import com.yupi.yoj.service.QuestionService;
import com.yupi.yoj.service.QuestionSubmitService;
import com.yupi.yoj.service.UserService;
import io.jsonwebtoken.lang.Collections;
import io.swagger.annotations.Scope;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author 46411
* @description 针对表【question(题目)】的数据库操作Service实现
* @createDate 2024-09-23 23:35:18
*/
@Service
@Transactional
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question>
    implements QuestionService{

//    @Autowired
    private QuestionSubmitService questionSubmitService;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    UserService userService;

    @Autowired
    public QuestionServiceImpl(@Lazy QuestionSubmitService questionSubmitService) {
        this.questionSubmitService = questionSubmitService;
    }

    @Override
    public void addQuestion(Question question) {
        Question questionbyId = this.getById(question.getId());
        if (questionbyId != null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目已存在");
        }
        if (!this.save(question)) throw new BusinessException(ErrorCode.SYSTEM_ERROR, "添加题目失败");
    }

    @Override
    public void updateQuestionById(Question question) {
        if (question == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        UpdateWrapper<Question> questionUpdateWrapper = new UpdateWrapper<>();
        String title = question.getTitle();
        String content = question.getContent();
        String tags = question.getTags();
        String answer = question.getAnswer();
        if (StringUtils.isAnyBlank(title, content, tags, answer)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        questionUpdateWrapper.set("title", title);// 设置要更新的字段
        questionUpdateWrapper.set("content", content);// 设置要更新的字段
        questionUpdateWrapper.set("tags", question.getTags());// 设置要更新的字段
        questionUpdateWrapper.set("answer", question.getAnswer());// 设置要更新的字段
        String judgeconfig = question.getJudgeconfig();
        // 如果judgeCase 为空 表示不需要修改
        if (!StringUtils.isAnyBlank(judgeconfig)) {
            questionUpdateWrapper.set("judgeconfig", judgeconfig);// 设置要更新的字段
        }
        Long id = question.getId();
        if (id <= 0) throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        questionUpdateWrapper.eq("id", id); // 添加更新的条件
        if (!this.update(questionUpdateWrapper)) throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新题目失败");
    }

    @Override
    public void deleteQuestionById(Long id) {
        if (!this.removeById(id)) throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除题目失败");
    }

    @Override
    public QuestionVO getQuestionById(Long id) {
        if (id == null || id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        Question question = this.getById(id);
        if (question == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目不存在");
        }
        QuestionVO questionVO = new QuestionVO();
        BeanUtils.copyProperties(question, questionVO);
        String tags = question.getTags();
        if (!StringUtils.isAnyBlank(tags)) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                String[] tagsArr = objectMapper.readValue(tags, String[].class) ;
                questionVO.setTags(tagsArr);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        String judgecaseStr = question.getJudgecase();
        String judgeConfigStr = question.getJudgeconfig();
        if (!StringUtils.isAnyBlank(judgecaseStr, judgeConfigStr)) {
            JudgeCase judgeCaseList = JSONUtil.toBean(judgecaseStr, JudgeCase.class);
            JudgeConfig judgeConfigList = JSONUtil.toBean(judgeConfigStr, JudgeConfig.class);
            questionVO.setJudgecase(judgeCaseList);
            questionVO.setJudgeconfig(judgeConfigList);
        }else {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "判题信息不存在");
        }
        return questionVO;
    }

    @Override
    public QueryWrapper<Question> getQueryWrapper(QuestionQueryRequest questionQueryRequest) {
        if (questionQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();
        Long id = questionQueryRequest.getId();
        String title = questionQueryRequest.getTitle();
        Integer acceptednum = questionQueryRequest.getAcceptednum();
        Integer favournum = questionQueryRequest.getFavournum();
        Integer submitnum = questionQueryRequest.getSubmitnum();
        Long userId = questionQueryRequest.getUserid();
        Integer thumbnum = questionQueryRequest.getThumbnum();
        String tags = questionQueryRequest.getTags();
        if (tags != null) {
            // todo
        }
//        ThrowUtils.throwIf(id == null || id <= 0, ErrorCode.PARAMS_ERROR, "id不能小于0");
        if (title != null) queryWrapper.like("title", title);

        return queryWrapper;
    }

    public QuestionVO getQuestionVO(Question question) {
        QuestionVO questionVO = null;
        try {
            questionVO = new QuestionVO();
            BeanUtils.copyProperties(question, questionVO);
            String tags = question.getTags();
            if (StringUtils.isNotBlank(tags)) {
                String[] proTags = JSONUtil.parseArray(tags).toArray(new String[0]);
                if (proTags != null) questionVO.setTags(proTags);
            }else throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据库数据异常");

            String judgecase = question.getJudgecase();
            if (StringUtils.isNotBlank(judgecase)) {
                JSONObject jsonObject = JSONUtil.parseObj(judgecase);
                String inputStr = jsonObject.getStr("input");
                String outputStr = jsonObject.getStr("output");
                List<String> input = null;
                if (StringUtils.isNotBlank(inputStr)) {
                    input = JSONUtil.parseArray(inputStr).toList(String.class);
                }
                List<String> output = null;
                if (StringUtils.isNotBlank(inputStr)) {
                    output = JSONUtil.parseArray(outputStr).toList(String.class);
                }
                JudgeCase judgeCase = new JudgeCase();
                judgeCase.setInput(input);
                judgeCase.setOutput(output);

                if (judgeCase != null) questionVO.setJudgecase(judgeCase);
            }else throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据库数据异常");

            String judgeconfig = question.getJudgeconfig();
            if (StringUtils.isNotBlank(judgeconfig)) {
                JudgeConfig judgeConfig = JSONUtil.toBean(judgeconfig, JudgeConfig.class);
                if (judgeConfig != null) questionVO.setJudgeconfig(judgeConfig);
            }else throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据库数据异常");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return questionVO;
    }
    @Override
    public List<QuestionVO> getQuestionVO(List<Question> records) {
            List<QuestionVO> questionVOs = new LinkedList<>();
            for (int i = 0; i < records.size(); i++) {
                Question question = records.get(i);
                QuestionVO questionVO = getQuestionVO(question);
                questionVOs.add(questionVO);
                // 拿提交次数
                QueryWrapper<QuestionSubmit> questionSubmitQueryWrapper = new QueryWrapper<>();
                questionSubmitQueryWrapper.eq("questionId", question.getId());
                List<QuestionSubmit> questionList = questionSubmitService.list(questionSubmitQueryWrapper);
                questionVO.setSubmitnum(questionList.size());
                List<QuestionSubmit> acceptQuestionSubmitVOList = questionList.stream().filter(it -> it.getStatus() == 2).collect(Collectors.toList());
                if (!Collections.isEmpty(acceptQuestionSubmitVOList)) {
                    // 拿通过次数
                    questionVO.setSubmitnum(acceptQuestionSubmitVOList.size());
                }
            }
            return questionVOs;
    }

    @Override
    public List<QuestionVO> listQuestionByTagTitle(String title, String tag) {
        QueryWrapper<Question> questionVOQueryWrapper = new QueryWrapper<>();
        if(tag != null) questionVOQueryWrapper.like("tags", tag);
        if (title != null) questionVOQueryWrapper.eq("title", title);
        List<Question> questionList = this.list(questionVOQueryWrapper);
        return this.getQuestionVO(questionList);
    }

    @Override
    public List<Question> getQuestionListByTids(ContestQueryTeamListByTidsRequest contestQueryRequest) {
        ThrowUtils.throwIf(contestQueryRequest == null, ErrorCode.PARAMS_ERROR, "参数为空");
        QueryWrapper<Question> questionQueryWrapper = new QueryWrapper<>();
        List<Long> tids = contestQueryRequest.getTids();
        ThrowUtils.throwIf(CollectionUtils.isEmpty(tids), ErrorCode.PARAMS_ERROR, "参数为空");
        questionQueryWrapper.in("id", tids);
        return this.list(questionQueryWrapper);
    }


    @Override
    public Page<Question> searchFromEs(QuestionQueryRequest questionQueryRequest) {
        Long id = questionQueryRequest.getId();
        String tags = questionQueryRequest.getTags();
        String[] tagsList = null;
        if (StringUtils.isNotBlank(tags)) {
            tagsList = JSONUtil.parseArray(tags).toArray(new String[0]);
        }
        String content = questionQueryRequest.getContent();
        String title = questionQueryRequest.getTitle();

        String searchText = questionQueryRequest.getSearchText();

        // es 起始页为 0
        long current = questionQueryRequest.getCurrent() - 1;
        long pageSize = questionQueryRequest.getPageSize();
        String sortField = questionQueryRequest.getSortField();
        String sortOrder = questionQueryRequest.getSortOrder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 过滤
//        boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete", 0));
        if (id != null && id > 0) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("id", id));
        }
        // 必须包含所有标签
        if (ArrayUtil.isNotEmpty(tagsList)) {
            for (String tag : tagsList) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("tags", tag));
            }
        }
        // 包含任何一个标签即可
//        if (CollUtil.isNotEmpty(orTagList)) {
//            BoolQueryBuilder orTagBoolQueryBuilder = QueryBuilders.boolQuery();
//            for (String tag : orTagList) {
//                orTagBoolQueryBuilder.should(QueryBuilders.termQuery("tags", tag));
//            }
//            orTagBoolQueryBuilder.minimumShouldMatch(1);
//            boolQueryBuilder.filter(orTagBoolQueryBuilder);
//        }
        // 按关键词检索
        if (StringUtils.isNotBlank(searchText)) {
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", searchText));
//            boolQueryBuilder.should(QueryBuilders.matchQuery("description", searchText));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content", searchText));
            boolQueryBuilder.minimumShouldMatch(1);
        }
        // 按标题检索
        if (StringUtils.isNotBlank(title)) {
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", title));
            boolQueryBuilder.minimumShouldMatch(1);
        }
        // 按内容检索
      /*  if (StringUtils.isNotBlank(content)) {
            boolQueryBuilder.should(QueryBuilders.matchQuery("content", content));
            boolQueryBuilder.minimumShouldMatch(1);
        }*/
        // 排序
        SortBuilder<?> sortBuilder = SortBuilders.scoreSort();
        if (StringUtils.isNotBlank(sortField)) {
            sortBuilder = SortBuilders.fieldSort(sortField);
            sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC : SortOrder.DESC);
        }
        // 分页
        PageRequest pageRequest = PageRequest.of((int) current, (int) pageSize);
        // 构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest).withSorts(sortBuilder).build();
        SearchHits<QuestionEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, QuestionEsDTO.class);
        Page<Question> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());
        List<Question> resourceList = new ArrayList<>();
        // 查出结果后，从 db 获取最新动态数据（比如点赞数）
        if (searchHits.hasSearchHits()) {
            List<SearchHit<QuestionEsDTO>> searchHitList = searchHits.getSearchHits();
            List<Long> questionIdList = searchHitList.stream().map(searchHit -> searchHit.getContent().getId())
                    .collect(Collectors.toList());
            List<Question> questionList = baseMapper.selectBatchIds(questionIdList);
            if (questionList != null) {
                Map<Long, List<Question>> idPostMap = questionList.stream().collect(Collectors.groupingBy(Question::getId));
                questionIdList.forEach(questionId -> {
                    if (idPostMap.containsKey(questionId)) {
                        resourceList.add(idPostMap.get(questionId).get(0));
                    } else {
                        // 从 es 清空 db 已物理删除的数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(questionId), QuestionEsDTO.class);
                        System.out.println("delete post "+ delete);
                    }
                });
            }
        }
        page.setRecords(resourceList);
        return page;
    }

    @Override
    public Page<QuestionVO> getQuestionVOPage(Page<Question> questionPage, HttpServletRequest request) {
        List<Question> questionList = questionPage.getRecords();
        Page<QuestionVO> questionVOPage = new Page<>(questionPage.getCurrent(), questionPage.getSize(), questionPage.getTotal());
        if (CollUtil.isEmpty(questionList)) {
            return questionVOPage;
        }
        // 1. 关联查询用户信息
        Set<Long> userIdSet = questionList.stream().map(Question::getUserid).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 2. 已登录，获取用户点赞、收藏状态
        Map<Long, Boolean> postIdHasThumbMap = new HashMap<>();
        Map<Long, Boolean> postIdHasFavourMap = new HashMap<>();
        User loginUser = userService.getLoginUserPermitNull(request);
        if (loginUser != null) {
            Set<Long> questionIdSet = questionList.stream().map(Question::getId).collect(Collectors.toSet());
            loginUser = userService.getLoginUser(request);
            // 获取点赞
//            QueryWrapper<PostThumb> postThumbQueryWrapper = new QueryWrapper<>();
//            postThumbQueryWrapper.in("postId", postIdSet);
//            postThumbQueryWrapper.eq("userId", loginUser.getId());
//            List<PostThumb> postPostThumbList = postThumbMapper.selectList(postThumbQueryWrapper);
//            postPostThumbList.forEach(postPostThumb -> postIdHasThumbMap.put(postPostThumb.getPostId(), true));
            // 获取收藏
//            QueryWrapper<PostFavour> postFavourQueryWrapper = new QueryWrapper<>();
//            postFavourQueryWrapper.in("postId", postIdSet);
//            postFavourQueryWrapper.eq("userId", loginUser.getId());
//            List<PostFavour> postFavourList = postFavourMapper.selectList(postFavourQueryWrapper);
//            postFavourList.forEach(postFavour -> postIdHasFavourMap.put(postFavour.getPostId(), true));
        }
        // 填充信息
        List<QuestionVO> questionVOList = questionList.stream().map(post -> {
            QuestionVO questionoVO = QuestionVO.objToVo(post);
            Long userId = post.getUserid();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            questionoVO.setUser(userService.getUserVO(user));
           /* questionoVO.setThumbnum(postIdHasThumbMap.getOrDefault(post.getId(), false));
            questionoVO.setFavournum(postIdHasFavourMap.getOrDefault(post.getId(), false));*/
            return questionoVO;
        }).collect(Collectors.toList());
        questionVOPage.setRecords(questionVOList);
        return questionVOPage;
    }

}




